package lab.cadl.lirui.markdown.gui

import javafx.application.Platform
import javafx.beans.property.SimpleBooleanProperty
import javafx.event.EventHandler
import javafx.scene.input.TransferMode
import javafx.scene.layout.Priority
import javafx.scene.paint.Color
import javafx.scene.text.Font
import javafx.scene.text.FontWeight
import javafx.stage.FileChooser
import lab.cadl.lirui.markdown.core.OutputFormat
import lab.cadl.lirui.markdown.core.utils.DefaultRender
import tornadofx.*
import java.io.File
import kotlin.concurrent.thread

class MainView : View("  Markdown文件转换器 @哈哈爱护的吧") {
    private val defaultFont = Font("Consolas", 20.0)
    private val lastDocs: MutableList<File> = mutableListOf()
    private val canReconvert = SimpleBooleanProperty(false)

    private var templateFile : File? = null

    private val output = textflow {
        paddingAll = 10.0
        text("Initialized.\nDrag files or select files.\n") {
            fill = Color.GRAY
            font = defaultFont
        }
    }

    private val outputPane = scrollpane(fitToHeight = true, fitToWidth = true) {
        content = output
    }

    private val indicator = progressindicator {
        useMaxWidth = true
    }

    private fun chooseAndConvert() {
        val initialDir = if (lastDocs.size > 0) {
            lastDocs.last().parentFile
        } else {
            null
        }

        val files = chooseFile("请选择Markdown文件",
                arrayOf(FileChooser.ExtensionFilter("Markdown", "*.md")),
                initialDir,
                FileChooserMode.Multi)
        lastDocs.clear()
        lastDocs.addAll(files)
        canReconvert.value = lastDocs.isNotEmpty()
        convertFiles(files)
    }

    private val convertButton = button("打开文件") {
        useMaxWidth = true
        font = Font.font("微软雅黑", FontWeight.BOLD, 20.0)
        action {
            chooseAndConvert()
        }
    }

    private val redoConvertButton = button("重新渲染") {
        useMaxWidth = true
        font = Font.font("微软雅黑", FontWeight.BOLD, 20.0)
        hgrow = Priority.ALWAYS
        enableWhen(canReconvert)

        action {
            convertFiles(lastDocs)
        }
    }

    override val root = borderpane {
        prefWidth = 800.0
        prefHeight = 600.0

        top = vbox {
            menubar {
                menu("文件") {
                    item("打开文件并转换") {
                        action { chooseAndConvert() }
                    }
                    item("重新渲染") {
                        enableWhen(canReconvert)
                        action { convertFiles(lastDocs) }
                    }
                }
                menu("设置") {
                    item("选择模板文件") {
                        action { chooseTemplateFile() }
                    }
                }
            }
            hbox {
                useMaxWidth = true

                this += convertButton
                this += redoConvertButton
            }
        }

        center = outputPane
        bottom = indicator
    }

    init {
        root.onDragOver = EventHandler { event ->
            if (event.gestureSource != root &&
                    event.dragboard.hasFiles() &&
                    event.dragboard.files.all { it.toString().lowercase().endsWith(".md") }) {
                event.acceptTransferModes(*TransferMode.COPY_OR_MOVE)
            }

            event.consume()
        }

        root.onDragDropped = EventHandler { event ->
            if (event.gestureSource != root &&
                    event.dragboard.hasFiles() &&
                    event.dragboard.files.all { it.toString().lowercase().endsWith(".md") }) {
                lastDocs.clear()
                lastDocs.addAll(event.dragboard.files)
                convertFiles(event.dragboard.files)
            }

            event.isDropCompleted = true
            event.consume()
        }

        indicator.hide()
    }

    private fun convertFiles(files: List<File>) {
        if (files.isEmpty()) {
            return
        }

        convertButton.isDisable = true
        canReconvert.value = false

        thread {
            try {
                var count = 0

                Platform.runLater {
                    indicator.show()
                    indicator.progress = 0.0
                }

                files.forEach {
                    Platform.runLater {
                        reportConvertStatus(it, null, "→")
                    }

                    val outputFile = convert(it)
                    count += 1

                    Platform.runLater {
                        reportConvertStatus(it, outputFile, "√", Color.DARKGREEN)
                        indicator.progress = count.toDouble() / files.size
                    }
                }

                Platform.runLater {
                    indicator.progress = 1.0
                }
            } catch (ex: Exception) {
                Platform.runLater {
                    output += text(ex.toString() + "\n") {
                        font = Font(20.0)
                        fill = Color.DARKRED
                    }
                }
            } finally {
                Platform.runLater {
                    canReconvert.value = true
                    convertButton.isDisable = false
                }
            }
        }
    }

    private fun chooseTemplateFile() {
        val initialDir = templateFile?.parentFile

        val files = chooseFile("请选择模板文件",
                arrayOf(FileChooser.ExtensionFilter("Word 2007 Document", "*.docx")),
                initialDir,
                FileChooserMode.Single)
        if (files.isNotEmpty()) {
            templateFile = files[0]
        }
    }

    private fun reportConvertStatus(source: File, target: File?, status: String, statusColor: Color = Color.BLACK) {
        output += text("[ $status ] ") {
            fill = statusColor
            font = defaultFont
        }

        output += text(source.toString()) {
            fill = Color.DARKBLUE
            font = defaultFont
        }

        if (target != null) {
            output += text("  →  ") {
                fill = Color.GRAY
                font = defaultFont
            }

            output += text(target.toString()) {
                fill = Color.GREEN
                font = defaultFont
            }
        }

        output += text("\n")
    }

    private fun convert(inputFile: File): File {
        val templateFileString = if (templateFile != null) {
            templateFile!!.toPath().toString()
        } else {
            ""
        }

        return DefaultRender().render(inputFile, templateFileString, OutputFormat.WORD)
    }
}